package com.gitee.feizns.explore.data_structure.array_and_string.sudoku;

import java.util.HashSet;
import java.util.Set;
import java.util.function.Predicate;

/**
 * @author feizns
 * @since 2019/10/24
 */
public class Main {

    //[[".","1","5",".",".",".",".",".","."],[".",".",".",".",".","2",".",".","."],[".","2",".","9",".",".",".",".","."],[".",".","4",".",".",".",".",".","."]]

    static char[][] BOARD = {
            {'.', '.', '.', '.', '5', '.', '.', '1', '.'},
            {'.', '4', '.', '3', '.', '.', '.', '.', '.'},
            {'.', '.', '.', '.', '.', '4', '.', '.', '2'},

            {'8', '.', '.', '.', '.', '.', '.', '2', '.'},
            {'.', '.', '2', '.', '7', '.', '.', '.', '.'},
            {'.', '1', '5', '.', '.', '.', '.', '.', '.'},

            {'.', '.', '.', '.', '.', '2', '.', '.', '.'},
            {'.', '2', '.', '9', '.', '.', '.', '.', '.'},
            {'.', '.', '4', '.', '.', '.', '.', '.', '.'},
    };

    public static void main(String[] args) {
        System.out.println(isValid(BOARD));
    }

    public static boolean isValid(char[][] board) {
        return isValidAll3x3(board) && isValidAllRow(board) && isValidAllCol(board);
    }

    public static boolean isValidAll3x3(char[][] board) {
        for (int i = 0; i < board.length; i+=3) {
            for (int j = 0; j < board.length; j+=3) {
                if ( !isValid3x3(board, i, j) )
                    return false;
            }
        }
        return true;
    }

    public static boolean isValid3x3(char[][] board, int r, int c) {
        Set<Character> set = new HashSet<>();
        for (int i = r; i < r + 3; i++) {
            for (int j = c; j < c + 3; j++) {
                if ( isRepeatNum(set, board[i][j]) )
                    return false;
            }
        }
        return true;
    }

    public static boolean isValidAllRow(char[][] board) {
        return allTrue(i -> isValidRow(board, i));
    }

    public static boolean isValidRow(char[][] board, int r) {
        Set<Character> set = new HashSet<>();
        for (int col = 0; col < 9; col++) {
            if ( isRepeatNum(set, board[r][col]) )
                return false;
        }
        return true;
    }

    public static boolean isValidAllCol(char[][] board) {
        return allTrue(i -> isValidCol(board, i));
    }

    private static boolean allTrue(Predicate<Integer> test) {
        for (int i = 0; i < 9; i++) {
            if ( !test.test(i) )
                return false;
        }
        return true;
    }

    public static boolean isValidCol(char[][] board, int c) {
        Set<Character> set = new HashSet<>();
        for (int row = 0; row < 9; row++) {
            if ( isRepeatNum(set, board[row][c]) )
                return false;
        }
        return true;
    }

    private static boolean isRepeatNum(Set<Character> set, char c) {
        int size = set.size();
        if ( isNum(c) ) {
            set.add(c);
            return size == set.size();
        }
        return false;
    }

    private static boolean isNum(char c) {
        return c >= '0' && c <= '9';
    }

}
